
import 'dart:async';
import 'dart:math';

import 'package:animation_effect_demo/src/effects/base/base_effect.dart';
import 'package:animation_effect_demo/src/effects/effect_template.dart';
import 'package:animation_effect_demo/src/effects/text_operation.dart';
import 'package:animation_effect_demo/src/widget/text_frame_animation_painter.dart';
import 'package:flutter/material.dart';



class GalleryAnimationContainer extends StatefulWidget {

  final EffectOperation operation;

  final double? displayWidth;
  final double? displayHeight;
  final List<Point>? points;
  final ValueChanged<List<List<Color>>>? onEnterFrame;


  const GalleryAnimationContainer(
      {Key? key,
        required this.operation,
        this.displayWidth,
        this.displayHeight,
        this.points,
        this.onEnterFrame,
      })
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _GalleryAnimationContainerState();
}

class _GalleryAnimationContainerState extends State<GalleryAnimationContainer>
    with SingleTickerProviderStateMixin {
  int currentFrame = 0;
  Timer? timer;
  List<List<List<Color>>>? frames;
  int frameDuration = 50;

  @override
  void didUpdateWidget(covariant GalleryAnimationContainer oldWidget) {
    if (oldWidget.operation != widget.operation) {
      timer?.cancel();
      currentFrame = 0;
      getFrames().then((frameData) {
        frames = _transitionFrameData(frameData);
        startTimerFrames();
      });
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  void initState() {
    getFrames().then((frameData) {
      frames = _transitionFrameData(frameData);
      startTimerFrames();
    });

    super.initState();
  }

  List<List<List<Color>>>? _transitionFrameData(
      List<List<List<Color>>> frameData) {
    var responseFrames;
    if (widget.points?.isNotEmpty ?? false) {
      List<Point>? points = widget.points!;
      responseFrames = List.generate(frameData.length, (frameIndex) {
        List<List<Color>> tempFrame = List.generate(frameData[frameIndex].length, (columIndex) => List.generate(frameData[frameIndex][columIndex].length, (rowIndex) => const Color(0xFF272729)));
        for (int i = 0; i < points.length; i++) {
          Point point = points[i];
          var currentFrame = frameData[frameIndex];
          if (point.x < currentFrame.length &&
              point.y < currentFrame.first.length) {
            tempFrame[point.x.toInt()][point.y.toInt()] =
            frameData[frameIndex][point.x.toInt()][point.y.toInt()];
          }
        }
        return tempFrame;
      });
    } else {
      responseFrames = frameData;
    }
    return responseFrames;
  }

  Future<List<List<List<Color>>>> getFrames() async {
    final animationEffect = BaseEffect(EffectType.textEffect);
    List<List<List<Color>>> animationFrames = await animationEffect.getFrames(operation: widget.operation);
    return animationFrames;
  }

  void startTimerFrames() {
    if (frames?.isNotEmpty ?? false) {
      if (frames!.length > 1) {
        timer?.cancel();
        timer = Timer.periodic(Duration(milliseconds: frameDuration), (timer) {
          if (!mounted) {
            timer.cancel();
            return;
          }
          setState(() {
            currentFrame++;
            if (currentFrame > frames!.length - 1) {
              currentFrame = 0;
            }
          });
          widget.onEnterFrame?.call(frames![currentFrame]);
        });
      } else {
        setState(() {
          currentFrame = 0;
        });
        widget.onEnterFrame?.call(frames![currentFrame]);
      }
    }
  }

  @override
  void dispose() {
    timer?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return frames != null
        ? CustomPaint(
      painter: GalleryFrameAnimationPainter(
          frames!.isNotEmpty ? frames![currentFrame] : [],
      ),
      child: Container(),
    )
        : const Center(
      child: CircularProgressIndicator(),
    );
  }
}